package com.xms.sdk.extensions;

import cn.hutool.core.lang.Assert;
import com.xms.schema.entity.Attribute;
import com.xms.schema.entity.Entity;
import com.xms.schema.entity.RelationShip;
import com.xms.schema.extension.AttributeExt;
import com.xms.schema.service.attribute.IAttributeUnionFinderService;
import com.xms.schema.service.entity.IEntityFinderService;
import com.xms.schema.service.relationship.IRelationShipFinderService;
import com.xms.sdk.core.query.*;
import com.xms.sdk.query.QueryMetadataDescriptor;
import com.xms.utils.CollectionUtil;
import com.xms.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 查询表达式中的元数据
 * </p>
 *
 * @author migo
 * @since 2021/9/4
 */
@Service
public class QueryMetadataFinder implements IQueryMetadataFinder {
    private IEntityFinderService _entityFinderService;
    private IAttributeUnionFinderService _attributeUnionFinderService;
    private IRelationShipFinderService _relationShipFinderService;

    @Autowired
    public QueryMetadataFinder(IEntityFinderService entityFinderService
            , IAttributeUnionFinderService attributeUnionFinderService
            , IRelationShipFinderService relationShipFinderService) {
        _entityFinderService = entityFinderService;
        _attributeUnionFinderService = attributeUnionFinderService;
        _relationShipFinderService = relationShipFinderService;
    }

    @Override
    public QueryMetadataDescriptor getAll(QueryBase query) {
        Assert.notNull(query);
        Assert.notBlank(query.EntityName, "entityname must not be empty");
        QueryMetadataDescriptor result = getMetaData(query, true, true, true);

        return result;
    }

    @Override
    public List<Attribute> getAttributes(QueryBase query) {
        Assert.notNull(query);
        Assert.notBlank(query.EntityName);
        QueryMetadataDescriptor result = getMetaData(query, true, true, false);
        return result.attributeList;
    }

    @Override
    public List<Entity> getEntities(QueryBase query) {
        Assert.notNull(query);
        Assert.notBlank(query.EntityName);
        QueryMetadataDescriptor result = getMetaData(query, true, true, true);
        return result.entityList;
    }

    @Override
    public List<RelationShip> getRelationShips(QueryBase query) {
        Assert.notNull(query);
        Assert.notBlank(query.EntityName);
        QueryMetadataDescriptor result = getMetaData(query, false, false, true);
        return result.relationShipList;
    }

    private void getLinkMetaData(QueryMetadataDescriptor result, LinkEntity linkEntity, boolean getEntities, boolean getAttributes, boolean getRelationShips) {
        //关联实体
        if (getEntities) {
            if (!result.entityList.stream().anyMatch(x -> x.getName().equalsIgnoreCase(linkEntity.LinkToEntityName))) {
                Entity entity = _entityFinderService.getByName(linkEntity.LinkToEntityName);
                result.entityList.add(entity);
            }
        }
        //关联实体字段
        if (getAttributes) {
            List<Attribute> leAttributes = _attributeUnionFinderService.getByEntityName(linkEntity.LinkToEntityName);
            //_attributeList.addAll(leAttributes);
            if (CollectionUtil.notEmpty(leAttributes)) {
                if (!linkEntity.Columns.AllColumns && linkEntity.Columns.Columns.size() > 0) {
                    for (String column : linkEntity.Columns.Columns) {
                        if (leAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase(column))) {
                            result.attributeList.add(leAttributes.stream().filter(x -> x.getName().equalsIgnoreCase(column)).findFirst().get());
                        }
                    }
                } else {
                    result.attributeList.addAll(leAttributes);
                }
            }
            parseFilter(result, result.entityList.stream().filter(n -> n.getName().equalsIgnoreCase(linkEntity.LinkToEntityName)).findFirst().get(), leAttributes, linkEntity.LinkCriteria);

        }
        //关系
        if (getRelationShips) {
            RelationShip rs = _relationShipFinderService.getByName(linkEntity.EntityAlias);
            result.relationShipList = new LinkedList<>();
            if (rs != null)
                result.relationShipList.add(rs);

            /*if (CollectionUtil.notEmpty(linkEntity.LinkEntities)) {
                for (LinkEntity le : linkEntity.LinkEntities) {
                    getLinkMetaData(le, getEntities, getAttributes, getRelationShips);
                }
            }*/
        }
        if (CollectionUtil.notEmpty(linkEntity.LinkEntities)) {
            for (LinkEntity le : linkEntity.LinkEntities) {
                getLinkMetaData(result, le, getEntities, getAttributes, getRelationShips);
            }
        }
    }

    private void parseFilter(QueryMetadataDescriptor result, Entity entityMetaData, List<Attribute> attributes, FilterExpression filter) {
        if (CollectionUtil.notEmpty(filter.Conditions)) {
            for (ConditionExpression cd : filter.Conditions) {
                getConditionAttribute(result, entityMetaData, attributes, cd);
            }
            if (CollectionUtil.notEmpty(filter.Filters)) {
                for (FilterExpression item : filter.Filters) {
                    parseFilter(result, entityMetaData, attributes, item);
                }
            }
        } else if (CollectionUtil.notEmpty(filter.Filters)) {
            for (FilterExpression item : filter.Filters) {
                parseFilter(result, entityMetaData, attributes, item);
            }
        }
    }

    private void getConditionAttribute(QueryMetadataDescriptor result, Entity entityMetaData, List<Attribute> attributes, ConditionExpression conditionNode) {
        boolean isLinkCondition = conditionNode.AttributeName.indexOf('.') > 0; //是否按关联实体的字段过滤
        Attribute attribute = null;
        if (isLinkCondition) {
            String[] arr = StringUtil.splitSafe(conditionNode.AttributeName, "[.]");
            RelationShip relationShip = result.relationShipList.stream().filter(x -> x.getName().equalsIgnoreCase(arr[0])).findFirst().orElse(null);
            if (relationShip != null) {
                attribute = attributes.stream().filter(x -> x.getEntityid().equals(relationShip.getReferencedentityid()) && x.getName().equalsIgnoreCase(arr[1])).findFirst().orElse(null);
            }
        } else {
            attribute = attributes.stream().filter(x -> x.getEntityid().equals(entityMetaData.getEntityid())
                    && x.getName().equalsIgnoreCase(conditionNode.AttributeName)).findFirst().orElse(null);
        }
        if (attribute != null) {
            result.attributeList.add(attribute);
        }
    }

    // 获取关联的实体及字段元数据
    private QueryMetadataDescriptor getMetaData(QueryBase query, boolean getEntities, boolean getAttributes, boolean getRelationShips) {
        QueryMetadataDescriptor result = new QueryMetadataDescriptor();
        //保存主实体
        if (getEntities) {
            result.entityList = new LinkedList<>();
            result.entityList.add(_entityFinderService.getByName(query.EntityName));
        }
        //获取实体所有字段
        if (getAttributes) {
            //_attributeList = _attributeFinderService.getByEntityName(query.EntityName);
            List<Attribute> entityAttributes = _attributeUnionFinderService.getByEntityName(query.EntityName);
            result.attributeList = new LinkedList<>();
            if (query instanceof QueryExpression) {
                QueryExpression queryExp = (QueryExpression) query;
                if (!queryExp.ColumnSet.AllColumns && CollectionUtil.notEmpty(queryExp.ColumnSet.Columns)) {
                    for (String column : queryExp.ColumnSet.Columns) {
                        if (entityAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase(column))) {
                            result.attributeList.add(entityAttributes.stream().filter(x -> x.getName().equalsIgnoreCase(column)).findFirst().get());
                        }
                    }
                    if (!result.attributeList.stream().anyMatch(x -> x.getIsprimaryfield()) && entityAttributes.stream().anyMatch(x -> x.getIsprimaryfield())) {
                        result.attributeList.add(entityAttributes.stream().filter(x -> x.getIsprimaryfield()).findFirst().get());
                    }
                    if (!result.attributeList.stream().anyMatch(x -> AttributeExt.typeIsPrimaryKey(x))) {
                        result.attributeList.add(entityAttributes.stream().filter(x -> AttributeExt.typeIsPrimaryKey(x)).findFirst().get());
                    }
                } else {
                    result.attributeList = entityAttributes;
                }
                if (queryExp.Criteria != null) {
                    parseFilter(result, result.entityList.stream().filter(n -> n.getName().equalsIgnoreCase(queryExp.EntityName)).findFirst().get()
                            , entityAttributes, queryExp.Criteria);
                }
            } else if (query instanceof QueryByAttribute) {
                QueryByAttribute queryExp = (QueryByAttribute) query;
                if (!queryExp.ColumnSet.AllColumns && CollectionUtil.notEmpty(queryExp.ColumnSet.Columns)) {
                    for (String column : queryExp.ColumnSet.Columns) {
                        if (entityAttributes.stream().anyMatch(x -> x.getName().equalsIgnoreCase(column))) {
                            result.attributeList.add(entityAttributes.stream().filter(x -> x.getName().equalsIgnoreCase(column)).findFirst().get());
                        }
                    }
                    result.attributeList.add(entityAttributes.stream().filter(x -> x.getIsprimaryfield()).findFirst().get());
                    result.attributeList.add(entityAttributes.stream().filter(x -> AttributeExt.typeIsPrimaryKey(x)).findFirst().get());
                } else {
                    result.attributeList = entityAttributes;
                }
            }
        }

        //link entities
        if (query instanceof QueryExpression) {
            QueryExpression queryExp = (QueryExpression) query;
            if (CollectionUtil.notEmpty(queryExp.LinkEntities)) {
                for (LinkEntity le : queryExp.LinkEntities) {
                    getLinkMetaData(result, le, getEntities, getAttributes, getRelationShips);
                }
            }
        }
        return result;
    }
}
